You should do these problems on paper or mentally first, and only THEN check the solution.
First we review how non-local variable references are resolved in Java.
NOTE: There will be no problems on Midterm 2 about Python or Java, but this is fundamental to understanding scope, and I suggest you go through them if you don't know how scope works.
5.1. Show what the following Java program prints out.
public class Main { static int n = 2; static int test(int k) { int n = 5; return n + k; } public static void main(String[] args) { int n = 10; System.out.println(n); System.out.println(test(n)); } }
5.2. Show what the following Java program prints out.
public class Main { static int n = 2; static int test(int k) { // int n = 5; -- Note this line is commented out return n + k; } public static void main(String[] args) { int n = 10; System.out.println(n); System.out.println(test(n)); } }
5.3. Show what the following Java program prints out.
public class Main { static int n = 2; static int test(int k) { // int n = 5; Note that this line is commented out return n + k; } public static void main(String[] args) { // int n = 10; Note that this line is commented out System.out.println(n); System.out.println(test(n)); } }
5.4. Show what the following Java program prints out.
public class Main { static int n = 0; static int test(int k) { n = n + 1; return n + k; } public static void main(String[] args) { int n = 10; System.out.println(test(n)); n = 100; System.out.println(test(n)); n = 1000; System.out.println(test(n)); } }
5.5. Show what the following Java program prints out.
public class Main { static int n = 0; static int test(int k) { n = n + 1; return n + k; } public static void main(String[] args) { n = 10; System.out.println(test(n)); int n = 100; System.out.println(test(n)); n = 1000; System.out.println(test(n)); } }
5.6. Show what the following Python program prints out.
n = 2 def test(k): n = 5 return n + k def main(): n = 10 print(n) print(test(n)) main()
5.7. What happens with the following Python program and why? (It attempts to simulate the Java program in 5.4.)
n = 0 def test(k): n = n + k return n + k def main(): n = 10 print(test(n)) n = 100 print(test(n)) n = 1000 print(test(n)) main()
5.8. How do we fix the problem in the previous problem so that it behaves as the Java program in 5.4?
For Midterm Two, I want you to know how dynamic vs lexical/static scoping works in Haskell, that is, what actually happens in Haskell, and what would happen if Haskell used dynamic scoping. There will be no questions about Python or Java, just Haskell examples, and just about what happens when you define functions and use those definitions. There will be nothing about the REPL's way of handling definitions, and the examples below use the REPL just for convenience; they might equally have been written in a file. The following exercises which show Haskell code are intended to illustrate the kinds of problems you might see on the exam. The Python questions are just for comparison (since I assume you know Python).
In problems 5.9 - 5.20, we show that with regard to the definitions made in the top level read-eval-print-loop, Python uses dynamic scoping and Haskell uses lexical scoping.
5.9. Show what the following Python code prints out.
n = 5 def test(k): return n + k print(test(10)) n = 10 print(test(10))
5.10. Show what the following Haskell code prints out.
Prelude> n = 5 Prelude> test k = n + k Prelude> test 10 15 Prelude> n = 10 Prelude> test 10 ??
Note: There is nothing special about using the REPL to do these kinds of examples, and the last example could just have easily been written in a file as:
ex5_10a = let n = 5 in let test k = n + k in test 10 ex5_10b = let n = 5 in let test k = n + k in let n = 10 in test 10
5.10b. What's the point of these last two problems?
5.11. Show what the following Python code prints out.
n = 0 def test(k): n = 10 def localTest(i): return n + k + i return localTest(10*k) print(test(10)) n = 1000 print(test(10))
5.12. Show what the following Python code prints out.
n = 0 def test(k): # n = 10 // this line commented out def localTest(i): return n + k + i return localTest(10*k) print(test(10)) n = 1000 print(test(10))
5.13. Show what the following Haskell code prints out.
Prelude> :set +m Prelude> n = 0 Prelude> test k = let n = 10 Prelude| localTest i = n + k + i Prelude| in (localTest 10)*k Prelude> test 10 300 Prelude> n = 1000 Prelude> test 10 ???
5.14. Show what the following Haskell code prints out.
Prelude> n = 0 Prelude> test k = let localTest i = n + k + i Prelude| in (localTest 10)*k Prelude> test 10 200 Prelude> n = 1000 Prelude> test 10 ???
5.15. Show what the following Haskell code prints out.
Prelude> n = 1 Prelude> g i = n + i Prelude> f func k = func (10*k) Prelude> f g 10 101 Prelude> n = 1000 Prelude> f g 10 ???
5.16. Show what the following Haskell code prints out.
Prelude> n = 1 Prelude> g i = n + i Prelude> f func k = func (10*k) Prelude> f g 10 101 Prelude> n = 1000 Prelude> f g 10 101 Prelude> f' func k = let n = 10 in func(10*k) Prelude> f' g 10 ???
5.17. Show what the following Haskell code prints out.
Prelude> n = 1 Prelude> f = \x -> let k = n in x * k Prelude> f 10 10 Prelude> n = 10 Prelude> f 10 ??
5.18. Show what the following Python code prints out. (= 5.15)
n = 1 def g(i): return n + i def f(func,k): return func (10*k) print(f(g,10)) n = 1000 print(f(g,10))
5.19. Show what the following Python code prints out. (= 5.16)
n = 1 def g(i): return n + i def f(func,k): return func (10*k) print(f(g,10)) n = 1000 print(f(g,10)) def fPrime(func,k): return func(10*k) print(fPrime(g,10))
5.20. Show what the following Python code prints out. (= 5.17)
n = 1 def f(x): k = n return x * k print(f(10)) n = 10 print(f(10))
In the remaining problems, we show that with regard to the definitions made locally (not in the REPL), both Python and Haskell use lexical scoping.
5.21. Show what the following Haskell code prints out and explain where the binding for n in the function h comes from.
Prelude> f func x = let n = 1 in func (x + n) Prelude> g x = let n = 10 Prelude| in let h y = n + y Prelude| in f h x Prelude> g 0 ??
5.22. What would be the value produced in the last problem if Haskell used dynamic scoping? Explain carefully.
5.23. What is the value printed by the following Python program and what does it say about the scope rules used for local variables (not defined in REPL) in Python?
def test (func,x): n = 2 return func(x+n,x-n) def tryIt(x,n): def why(x,y): return n * x + y return test(why,x) print(tryIt(1,10))
5.24. What would be the value produced if Python used dynamic scoping in the last example? Where does the "free variable capture" take place?
5.25. Show what the following Haskell code prints out and explain where the binding for n in the function h comes from.
-- In the file test.hs f :: (Integer -> Integer) -> Integer -> Integer f g x = let n = 1 in g ((\n -> g (x + n)) 100) test :: Integer -> Integer test x = f g x where n = 3 g = \x -> n + x Main> test 1000 ????
5.26. What would be the value produced in the last problem if Haskell used dynamic scoping? Explain carefully.
5.27. What is the value printed by the following Python program and what does it say about the scope rules used for local variables (not defined in REPL) in Python?
def f (func,x): n = 1 return func(x+n) def g(x): n = 10 def h(y): return n + y return f(h,x) print(g(0))
5.28. What would be the value produced if Python used dynamic scoping to find the binding for the non-local variable n when h was evaluated inside the function f?
5.29. Does the following code cause an error in Python (i.e., before you call the function f)?
def g(func,x): n = 1 return func(x+n) def f(x): return n + x
5.30. Does the following code cause an error in Python (i.e., AFTER you call the function f)?
def g(func,x): n = 1 return func(x+n) def f(x): return n + x print(g(f,0))
5.31. Does the following code cause an error in Haskell (i.e., before you call the function f)?
def g(func,x): n = 1 return func(x+n) def f(x): return n + x
5.32. What accounts for the differing behavior in Haskell and Python as shown in the last three problems?